//***************************************************************************//
//* 版权所有  www.sh-easy.com
//*
//* 内容摘要：网络基础API
//*	
//* 当前版本：V1.0		
//* 作    者：zhfayuan
//* 完成日期：2015-12-26
//**************************************************************************//

#if !defined(SDSOCKET_H)
#define SDSOCKET_H
#include "SDThread.h"
#include "SDMutex.h"
#include "SDMessage.h"
#include "SDEventGroup.h"


#define  SOCKET_INIT_TYPE_VAIL									0x01  // 连接无效

#define  SOCKET_INIT_TYPE_CONNECT								0x02  // 创建类型
#define  SOCKET_INIT_TYPE_CONNECT_ACK							0x03  // 回应包类型

#define  SOCKET_INIT_TYPE_RECONNECT								0x04  // 重新连接类型
#define  SOCKET_INIT_TYPE_RECONNECT_ACK							0x05  // 重连回应

#define  SOCKET_INIT_TYPE_SER_EXIST								0x06  // 测试服务器是否存在类型
#define  SOCKET_INIT_TYPE_SER_EXIST_ACK							0x07  // 测试服务器是否存在类型


#define  SOCKET_RECIVE_STATUS_OK								1
#define  SOCKET_RECIVE_STATUS_FAIL								2
#define  SOCKET_RECIVE_STATUS_RECONNECT_WAIT					3
#define  SOCKET_RECIVE_STATUS_RECONNECT_SUCCESS					4

#define  SOCKET_SEND_OUTTIME									1   // 发送超时时间，单位为秒
#define  SOCKET_RECIVE_OUTTIME									20  // 等待重连时间，单位为秒

#define  SERVER_SEND_CONNECT_TEST_COUNT							4	// 服务器发送测试网络速度的次数(在ip优选的时候使用)

#define	 TCP_SOCKET_COMMON_CLIENT								0
#define  TCP_SOCKET_COMMON_SERVER								1

// 专用于媒体服务器登录域服务器时的专属参数
typedef struct ConnectParamsForMediaServer
{
	UINT	unIPFirst;
	UINT	unIPNetTypeFirst;
	UINT	unIPSecond;
	UINT	unIPNetTypeSecond;
	UINT	unServerId;
	UINT    unServerType;
}ConnectParamsForMediaServer;

// 客户端连接协商消息定义
#define CRC_CODE_FOR_CONNECT_MSG								0x123456AB
typedef struct stConnectMsg
{
	ConnectParamsForMediaServer tMediaServerParams; // 网络配置参数集合(暂时只有媒体服务器connet域服务器时才会用到，其他情况都会舍弃)
	UINT   byCmd : 8;			  // 命令ID号
	UINT   unReserved:24;		  // 保留字节(此字节没有完美的32个bit位)
	int    nClientIndex;		  // 客户端在服务器上的Client对象标识，具备唯一性
	UINT   unOther;				  // 附属数据
	UINT   unCrcCode;			  // 有效性校验
}ConnectInitMsg;


/*
 *  此类为网络通讯的全局初始化接口，此类对象在整个程序中只能一个，必须放在程序main函数中
 */
class CSDNetInit
{
public:
	CSDNetInit();
	~CSDNetInit();
};

#define   SDARRAY_BLOCK_SIZE									1024
class CSDArray
{
public:
	CSDArray();
	~CSDArray();

public:
	int  GetSize();
	void *GetAt(int nPosi);
	void SetAt(int nPosi, void *pValue);

private:
	int      m_nMaxSize;
	void     **m_data;
};

//非阻塞版connect支持通过回调获取外部退出请求,返回1时表示外部请求退出
typedef int (*Interrupt_Callback)(void*);

class CSDSocket
{
public:
	CSDSocket();
	CSDSocket(char *strName);
	virtual ~CSDSocket();

private:
	void mfIniMember();
	
public:
	//通用API
    static BOOL single_recive_available(int nsockId, int nSec);
	static BOOL single_recive(int nsockId, char *strbuf, int nlen,BOOL bOuttimeErr = FALSE,int timedout_sec = 10);
	static BOOL single_recive_raw_outtime(int nsockId, int len, char *buf, int nOutTime = 0);
	static BOOL single_recive_raw(int nsockId, int len, char *buf);
	static BOOL single_send(int nsockId, char *strbuf, int nlen);
	static int  single_CreateServerSocket(USHORT shPort);
	static BOOL single_AcceptClient(int skServer, int &nClientFd, UINT &unIp);

	static void single_close_sock(int nsockId);
	static int  single_connect(char *strIp, int nPortId, int nTimeout = 0, 
							Interrupt_Callback interrupt_callback = NULL, void* opaque_callback = NULL);
	static int  single_no_block_connect(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, 
							Interrupt_Callback interrupt_callback, void* opaque_callback);
	static int  single_no_block_recv(int fd, char *buffer, int buflen, mysockaddr *from, int *fromlen, 
							Interrupt_Callback interrupt_callback, void* opaque_callback);

	static void single_set_keep_live(int nsockId, UINT unInterval, UINT unTime);
	static BOOL single_set_defaut_parameter(int nsockId);
	static BOOL single_set_send_timeout(int nsockId, int ntime);
	static BOOL single_set_recive_timeout(int nsockId, int ntime);

	static UINT single_GetLocalIp(int sockfd);
	static BOOL single_IsAddress( const char *ipstr);
	static BOOL single_IsPublicIP(UINT unIp);
	static BOOL single_IsPublicIP(char *strIp);
	static char* single_ForUrlGetIp(const char *strUrl);
	static char *single_GetExportIp(char *strRemoteIp = NULL);
	static BOOL single_set_socket_qos(int sockfd, int tos, int cos);


public:
	//带拼包功能的TCP接收
	static int  RecivePerNetBlock(int nsockId, char *&buf, int &nLen);
	//带拆包功能的TCP发送
	static BOOL SendPerNetBlock(int nsockId, char *buf, int nLen);
	//接收一个NET_BLOCK大小的数据，超时返回错误
	static BOOL ReceiveOneNetBlock(int nsockId, char *strbuf, int nlen);
	//发送一个小于传输负载的TCP数据包
	static BOOL SendOneNetBlock(int nsockId, int len, char *buf);

	static BOOL SendDynamicLen(int nsockId, char *buf, int nLen);
	static int  FindTcpDataPackHead(char *buf, int nLen);
	static int  ReceiveDynamicLen(int nsockId, char *PackArr[], int anPackLen[], int nMaxPacks);
	static BOOL SendCloseCmd(int nsockId);

	virtual BOOL sdsend(PACK_MESSAGE* pack) = 0;
	virtual BOOL sdsend(int nLen, char *buf) = 0;
	virtual void Command(PACK_MESSAGE *pack) = 0;
	virtual BOOL RespondPackMessage(PACK_MESSAGE *pack) = 0;
	virtual BOOL IsWork() = 0;
	virtual BOOL CreateTcpResource(int nsock, UINT unIp, ConnectInitMsg *pMsg) = 0;
	virtual BOOL ReinitTcpResource(int nsock, UINT unIp, ConnectInitMsg *pMsg) = 0;
	virtual int  GetSynRetBuf(PACK_MESSAGE* pack, int nWaitTime = MAX_LEN_OUT_TIME);
	virtual void UpdateSynRetBuf(PACK_MESSAGE* pack);
	virtual void SetName(char *strName);
	virtual void ProcessReciveData(int nLen, BYTE *byBuf);
	virtual void Close();

	void  ReleaseCurrentSynchEvent();
	BOOL Access();
	void UnAccess();
	UINT GetAccesCount();

private:
	static   int RespondProcessThread(char* pBuf, void *pObject);
	void     mfProcessRespond(PACK_MESSAGE* pack);

private:
	static char           m_strPrtTag[];

private:
	CSDEventGroup         m_SynEvent;
	CSDArray              m_SynArray;
	void*                 m_SynRetBufCs;
	CSDThreadProcessData  m_RespondProcess;
	UINT                  m_unWaitSeq; // 正在等待的回应消息ID
	char                  m_strName[32];

	//用于外部访问的保护，比如外部在获取了本对象指针后，再使用过程中，本对象被析构，会造成异常
	CSDMutexX  m_csAccess;
	UINT       m_unAccessCnt; // 访问的次数
	BOOL	   m_bDeleted;
};

#endif // !defined(SDSOCKET_H)
